﻿@using System.IO.Ports;
@using zy_simu.Data
@inject SimuCfg emu_cfg
@inject DeviceSnap dev_snap

<style>
    #div-hardware-panel {
        position: relative;
        border: 1px solid #000;
        border-radius: 5px;
        /*width: calc(var(--panel-width)*1.2);*/
        /*height: calc(var(--panel-height)*2);*/
        /*overflow: hidden;*/
        margin: 5px;
        padding: 5px;
    }

    .btn {
        --bs-btn-padding-x: .2rem;
    }
</style>

<div class="row" style="margin-left: 0px">
    <div class="col-8"> <h5>设备模拟控制台</h5> </div>
</div>

<div id="div-hardware-panel">
    <div class="row" style="margin-left: 0px; font-size: 18px">
        <div class="col-2"> <p>IO状态：</p> </div>
        <div class="col-2"> <i class="fas fa-snowflake" style="@(io_motor_state? "color: red" : "color: dimgrey")"></i> </div>
        <div class="col-2"> <i class="fas fa-fan" style="@(io_fan_state? "color: red" : "color: dimgrey")"></i> </div>
        <div class="col-2"> <i class="fas fa-mug-hot" style="@(io_heater_state? "color: red" : "color: dimgrey")"></i> </div>
        <div class="col-2"> <i class="fas fa-cloud-rain" style="@(io_melt_state? "color: red" : "color: dimgrey")"></i> </div>
        <div class="col-2"> <i class="fas fa-lightbulb" style="@(io_light_state? "color: red" : "color: dimgrey")"></i> </div>
    </div>
    <div class="row" style="margin-left: 0px">
        <div class="col-3"><Checkbox TValue="bool" @bind-Value="@emu_cfg.pow" ShowAfterLabel="true" DisplayText="12V市电" Color="Color.Danger" /></div>
        <div class="col-3"><Checkbox TValue="bool" @bind-Value="@emu_cfg.battery" ShowAfterLabel="true" DisplayText="电池" /></div>
        <div class="col-3"><Checkbox TValue="bool" @bind-Value="@emu_cfg.sensor1" ShowAfterLabel=" true" DisplayText="温度传感器1" /></div>
        <div class="col-3"><Checkbox TValue="bool" @bind-Value="@emu_cfg.sensor2" ShowAfterLabel=" true" DisplayText="温度传感器2" /></div>
    </div>
    <div class="row" style="margin-left: 0px">
        <div class="col-4"> <Switch @bind-Value="@emu_cfg.local_switch" OnColor="Color.Danger" OnText="控制器开关" OffText="控制器开关" ShowInnerText="true"></Switch> </div>
        <div class="col-4"> <Switch @bind-Value="@emu_cfg.remote_switch" OnColor="Color.Danger" OnText="远程开关" OffText="远程开关" ShowInnerText="true"></Switch> </div>
    </div>
    <div class="row" style="margin-left: 0px">
        <div class="col-4"><Checkbox TValue="bool" @bind-Value="@emu_cfg.door_polarity" ShowAfterLabel="true" DisplayText="门磁极性" /></div>
        <div class="col-4"> <Switch @bind-Value="@emu_cfg.door1" OnColor="Color.Warning" OnText="门1开" OffText="门1关" ShowInnerText="true" IsDisabled="@IsDoor1Disabled"></Switch> </div>
        <div class="col-4"> <Switch @bind-Value="@emu_cfg.door2" OnColor="Color.Warning" OnText="门2开" OffText="门2关" ShowInnerText="true" IsDisabled="@IsDoor2Disabled"></Switch> </div>
    </div>
    <div class="row" style="margin-left: 0px">
        <div class="col-4"> <Switch @bind-Value="@emu_cfg.human" OnColor="Color.Warning" OnText="有人" OffText="无人" ShowInnerText="true" IsDisabled="@IsHumanDisabled"></Switch> </div>
    </div>
    <div class="row" style="margin-left: 0px">
        <div class="col-4"> <Switch @bind-Value="@emu_cfg.wifi" OnColor="Color.Warning" OnText="wifi信号" OffText="wifi信号" ShowInnerText="true"></Switch> </div>
    </div>
    <div class="row" style="margin-left: 0px">
        <div class="col-2" style="margin-right: 0px; padding-right: 0px"><p>箱体温度</p></div>
        <div class="col-4"><BootstrapInputNumber @bind-Value="@emu_cfg.box_tem" ShowButton="true" Color="Color.Warning" Step="1" Min="-100" Max="100" FormatString="#.#" /></div>
        <div class="col-2" style="margin-right: 0px; padding-right: 0px"><p>蒸发器温度</p></div>
        <div class="col-4"><BootstrapInputNumber @bind-Value="@emu_cfg.defrost_tem" ShowButton="true" Color="Color.Warning" Step="1" Min="-100" Max="100" FormatString="#.#" /></div>
    </div>

    <div class="row" style="margin-left: 0px">
        <div class="col-2" style="margin-right: 0px; padding-right: 0px">
            <p>箱体温度模拟</p>
        </div>
        <div class="col-4">
            <Select Color="Color.Warning" Items="BoxTemVelocityItems" @bind-Value="emu_cfg.BoxTemVelocity"></Select>
        </div>
        <div class="col-2" style="margin-right: 0px; padding-right: 0px">
            <p>蒸发温度模拟</p>
        </div>
        <div class="col-4">
            <Select Color="Color.Warning" Items="DefrostVelocityItems" @bind-Value="emu_cfg.DefrostVelocity"></Select>
        </div>
    </div>
    <div class="row" style="margin-left: 0px">
        <div class="col-2" style="margin-right: 0px; padding-right: 0px">
            <p>压机模拟</p>
        </div>
        <div class="col-4">
            <Select Color="Color.Warning" Items="CompVelocityItems" @bind-Value="emu_cfg.CompVelocity"></Select>
        </div>
    </div>
    <div class="row" style="margin-left: 0px">
        <div class="col-2" style="margin-right: 0px; padding-right: 0px"><p>4G信号</p></div>
        <div class="col-4"><BootstrapInputNumber @bind-Value="@emu_cfg._4g" ShowButton="true" Color="Color.Warning" Step="1" Min="0" Max="31" /></div>
        <div class="col-2" style="margin-right: 0px; padding-right: 0px"><p>电池电压</p></div>
        <div class="col-4"><BootstrapInputNumber @bind-Value="@emu_cfg.vbatt" ShowButton="true" Color="Color.Warning" Step="1" Min="-1" Max="4.5" FormatString="#.#" /></div>
    </div>
</div>

@code {
    // 定义一些常量
    private const int ADC_CHN_NTC1 = 0;
    private const int ADC_CHN_NTC2 = 1;
    private const int ADC_CHN_VBAT = 2;
    private const int ADC_CHN_VREF = 3;

    private bool io_motor_state = false;
    private bool io_fan_state = false;
    private bool io_heater_state = false;
    private bool io_melt_state = false;
    private bool io_light_state = false;

    // simu input adc data unit:mv
    // 基于<<传感器连线（8000002941）规格书>> [-40, +105]共计146项, -40 -- 62670 om; 0 -- 6495 om; 40 -- 1071 om; 105 -- 122
    // Modified by Kaygle -- 2024-04-02 -- 客户修改阻值表，增加低温到-50, [-50, +105]共计156项
    private static uint[] tp_tem_om_table = {
    121000, 113100, 105700, 98870, 92520, 86610, 81120, 76000, 71240, 66810,
    62670, 58818, 55225, 51871, 48740, 45815, 43082, 40527, 38138, 35902,
    33810, 31851, 30016, 28296, 26684, 25172, 23754, 22424, 21175, 20002,
    18900, 17865, 16892, 15976, 15116, 14306, 13544, 12826, 12150, 11513,
    10913, 10347, 9814, 9311, 8836, 8388, 7965, 7566, 7189, 6832,
    6495, 6175, 5872, 5586, 5316, 5060, 4818, 4589, 4372, 4167,
    3973, 3788, 3614, 3448, 3291, 3142, 3000, 2866, 2738, 2617,
    2502, 2392, 2288, 2189, 2095, 2005, 1920, 1838, 1761, 1687,
    1617, 1550, 1486, 1425, 1367, 1312, 1259, 1209, 1161, 1115,
    1071, 1029, 989, 950, 914, 879, 845, 813, 783, 753,
    725, 698, 673, 648, 624, 602, 580, 559, 539, 520,
    502, 484, 467, 451, 436, 421, 406, 392, 379, 367,
    354, 343, 331, 320, 310, 300, 290, 281, 273, 264,
    256, 248, 241, 233, 226, 219, 213, 206, 200, 194,
    189, 183, 178, 173, 167, 163, 158, 154, 149, 145,
    141, 137, 133, 129, 126, 122, };


    // 模拟压机降温速率
    //private string CompVelocity = "0";
    private IEnumerable<SelectedItem> CompVelocityItems { get; set; } = new[]
    {
        new SelectedItem ("0", "不模拟") { Active = true },
        new SelectedItem ("30", "30秒降1度"),
        new SelectedItem ("60", "60秒降1度"),
        new SelectedItem ("120", "120秒降1度"),
        new SelectedItem ("300", "300秒降1度"),
        new SelectedItem ("600", "600秒降1度"),
    };
    // 模拟箱体升温速率
    //private string BoxTemVelocity = "0";
    private IEnumerable<SelectedItem> BoxTemVelocityItems { get; set; } = new[]
    {
        new SelectedItem ("0", "不模拟") { Active = true },
        new SelectedItem ("60", "60秒升1度"),
        new SelectedItem ("120", "120秒升1度"),
        new SelectedItem ("300", "300秒升1度"),
        new SelectedItem ("600", "600秒升1度"),
        new SelectedItem ("1800", "1800秒升1度"),
    };
    // 模拟化霜蒸发器升温速率
    //private string BoxTemVelocity = "0";
    private IEnumerable<SelectedItem> DefrostVelocityItems { get; set; } = new[]
    {
        new SelectedItem ("0", "不模拟") { Active = true },
        new SelectedItem ("60", "60秒升1度"),
        new SelectedItem ("120", "120秒升1度"),
        new SelectedItem ("300", "300秒升1度"),
        new SelectedItem ("600", "600秒升1度"),
        new SelectedItem ("1800", "1800秒升1度"),
    };

    protected override void OnInitialized()
    {
        base.OnInitialized();
    }

    private static int simu_battery_plus = 0;

    private bool IsGPIOValid(uint gpio)
    {
        return ((gpio & 0x7fffffff) != 0);
    }
    private bool IsDoor1Disabled = false;
    private bool IsDoor2Disabled = false;
    private bool IsHumanDisabled = false;
    public void UpdateSimuData(DeviceSnap dbg)
    {
        if (emu_cfg.m0_mode == "仿真") // 模拟器选中，主动模拟
        {
            // update environment temperature
            UpdateBoxTem(dbg.st.comp_on_timer, dbg.st.comp_off_timer);
            // 参考电压
            dbg.adc[ADC_CHN_VREF] = 3300;
            // NTC1 采样电压
            uint idx = (uint)(emu_cfg.box_tem + 50);
            if (idx > 155) idx = 155; // 限定不要溢出, 共计146项
            int span_10x = emu_cfg.box_tem > 0 ? (int)((emu_cfg.box_tem * 10 + 0.5)) % 10 : (int)((emu_cfg.box_tem * 10 - 0.5)) % 10; // 正负四舍五入
            if (span_10x < 0)
                span_10x += 10;
            uint om = 0;
            if (emu_cfg.sensor1)
            {
                om = tp_tem_om_table[idx] - (tp_tem_om_table[idx] - tp_tem_om_table[idx + 1]) * (uint)span_10x / 10;
                dbg.adc[ADC_CHN_NTC1] = (ushort)(3300 * om / (10000 + om));
            }
            else  // 传感器错误
                dbg.adc[ADC_CHN_NTC1] = 3250;
            // NTC2 采样电压
            idx = (uint)(emu_cfg.defrost_tem + 50);
            if (idx > 155) idx = 155; // 限定不要溢出, 共计146项
            span_10x = emu_cfg.defrost_tem > 0 ? (int)((emu_cfg.defrost_tem * 10 + 0.5)) % 10 : (int)((emu_cfg.defrost_tem * 10 - 0.5)) % 10; // 正负四舍五入
            if (span_10x < 0)
                span_10x += 10;
            om = 0;
            if (emu_cfg.sensor2)
            {
                om = tp_tem_om_table[idx] - (tp_tem_om_table[idx] - tp_tem_om_table[idx + 1]) * (uint)span_10x / 10;
                dbg.adc[ADC_CHN_NTC2] = (ushort)(3300 * om / (10000 + om));
            }
            else  // 传感器错误
                dbg.adc[ADC_CHN_NTC2] = 3250;
            // 电池采样电压
            dbg.adc[ADC_CHN_VBAT] = (ushort)(emu_cfg.vbatt * 1000 * 510 / (510 + 147) + 0.5);

            // GPIO door 门磁开关接地, doP参数缺省0：开门时开关断开，关门时开关闭合
            if (emu_cfg.door_polarity)
                dev_snap.WriteGPIO(dev_snap.gpio_tb.det_door1, !emu_cfg.door1);
            else
                dev_snap.WriteGPIO(dev_snap.gpio_tb.det_door1, emu_cfg.door1);
            // 人流量
            dev_snap.WriteGPIO(dev_snap.gpio_tb.det_human, emu_cfg.human);

            // 系统开关
            dev_snap.WriteGPIO(dev_snap.gpio_tb.det_sys_switch, !emu_cfg.local_switch);
            // 市电
            dev_snap.WriteGPIO(dev_snap.gpio_tb.det_12v, emu_cfg.pow);

            // 电池
            simu_battery_plus++;            
            if (emu_cfg.battery)
                dev_snap.WriteGPIO(dev_snap.gpio_tb.batt_chrg, emu_cfg.battery);
            else if (simu_battery_plus % 4 == 0)
                dev_snap.WriteGPIO(dev_snap.gpio_tb.batt_chrg, true);  // 模拟充电芯片TC4056A 没有电池250ms一个脉冲
            else 
                dev_snap.WriteGPIO(dev_snap.gpio_tb.batt_chrg, false);  // 模拟充电芯片TC4056A 没有电池250ms一个脉冲
        }
        else if (dbg.pms.Length > 1) // 模拟器没选中，追踪真实外挂设备, 但是要等待dbg通讯数据准备好
        {
            if (emu_cfg.door_polarity)
                emu_cfg.door1 = !dev_snap.ReadGPIO(dev_snap.gpio_tb.det_door1);
            else
                emu_cfg.door1 = dev_snap.ReadGPIO(dev_snap.gpio_tb.det_door1);
            // 追踪系统开关
            emu_cfg.local_switch = !dev_snap.ReadGPIO(dev_snap.gpio_tb.det_sys_switch);
            // 追踪电源
            emu_cfg.pow = dev_snap.ReadGPIO(dev_snap.gpio_tb.det_12v);
            // 追踪传感器
            emu_cfg.sensor1 = ((dbg.st.alarm & (byte)(ZqAlarmFlag.ZQ_ALARM_SENSOR)) == 0);
            emu_cfg.sensor2 = ((dbg.st.alarm & (byte)(ZqAlarmFlag.ZQ_ALARM_DEFROST_SENSOR)) == 0);
            InvokeAsync(StateHasChanged);
        }
        IsDoor1Disabled = !IsGPIOValid(dev_snap.gpio_tb.det_door1);
        IsDoor2Disabled = !IsGPIOValid(dev_snap.gpio_tb.det_door2);
        IsHumanDisabled = !IsGPIOValid(dev_snap.gpio_tb.det_human);
        // 记录压机/风机/加热器等状态
        bool motor_state = io_motor_state;
        bool fan_state = io_fan_state;
        bool heater_state = io_heater_state;
        bool melt_state = io_melt_state;
        bool light_state = io_light_state;
        io_motor_state = (IsGPIOValid(dev_snap.gpio_tb.motor)) ? dev_snap.ReadGPIO(dev_snap.gpio_tb.motor) : false;
        io_fan_state = (IsGPIOValid(dev_snap.gpio_tb.condenser_fan)) ? dev_snap.ReadGPIO(dev_snap.gpio_tb.condenser_fan) : false;
        io_fan_state = (IsGPIOValid(dev_snap.gpio_tb.fan)) ? dev_snap.ReadGPIO(dev_snap.gpio_tb.fan) : false;
        io_heater_state = (IsGPIOValid(dev_snap.gpio_tb.heater)) ? dev_snap.ReadGPIO(dev_snap.gpio_tb.heater) : false;
        io_melt_state = (IsGPIOValid(dev_snap.gpio_tb.melt)) ? dev_snap.ReadGPIO(dev_snap.gpio_tb.melt) : false;
        io_light_state = (IsGPIOValid(dev_snap.gpio_tb.light)) ? dev_snap.ReadGPIO(dev_snap.gpio_tb.light) : false;
        if (io_motor_state != motor_state || io_fan_state != fan_state || io_heater_state != heater_state || io_melt_state != melt_state || io_light_state != light_state) // 刷新界面
            InvokeAsync(StateHasChanged);
    }
    public bool GetCat1Status(DeviceSnap dbg)
    {
        return dev_snap.ReadGPIO(dev_snap.gpio_tb.cat1);
    }
    private int last_comp_on_timer = 0;
    private int last_comp_off_timer = 0;
    private void UpdateBoxTem(int comp_on_timer, int comp_off_timer)
    {
        int cv = int.Parse(emu_cfg.CompVelocity);
        int bv = int.Parse(emu_cfg.BoxTemVelocity);
        int dv = int.Parse(emu_cfg.DefrostVelocity);

        float tem = emu_cfg.box_tem;
        if (comp_on_timer == 0) last_comp_on_timer = 0;
        if (comp_off_timer == 0) last_comp_off_timer = 0;
        if (cv != 0 && comp_on_timer > 0)
        {
            if ((comp_on_timer - last_comp_on_timer) >= (cv / 10))
            {
                tem -= 0.1f;
                last_comp_on_timer = comp_on_timer;
            }
        }
        else if (bv != 0 && comp_off_timer > 0)
        {
            if ((comp_off_timer - last_comp_off_timer) >= (bv / 10))
            {
                tem += 0.1f;
                last_comp_off_timer = comp_off_timer;
            }
        }
        if (tem != emu_cfg.box_tem)
        {
            emu_cfg.box_tem = tem;
            InvokeAsync(StateHasChanged);
        }

    }
    public void Start()
    {
        // emu_cfg.pow = true;
        InvokeAsync(StateHasChanged);
    }
    public void Stop()
    {
        // emu_cfg.pow = false;
        InvokeAsync(StateHasChanged);
    }
    public Dictionary<string, string> Snap()
    {
        Dictionary<string, string> dict = new Dictionary<string, string>();
        dict["压机"] = io_motor_state ? "1" : "0";
        dict["风机"] = io_fan_state ? "1" : "0";
        dict["制热"] = io_heater_state ? "1" : "0";
        dict["主动化霜"] = io_melt_state ? "1" : "0";
        dict["灯"] = io_light_state ? "1" : "0";
        return dict;
    }

}

@*
    电源开关, 本地控制器开关,
    箱体温度, 电池电压(-1 - 无电池), 门开关, 人感(随机n人/分钟)
    如果接cat1, 就灰掉: 远端开关, 4g信号强度, wifi信号有无
    外接灯,
*@